/* ----------------------------- Noble Steed Engine----------------------------*
Authors : Daniel Randle, Alex Bourne
Date Created : Mar 7 2013

File:
	nsmesh.h

Description:
	This file contains the NSMesh class which can be used to load meshes in from file
	and draw them using their attached shader
*---------------------------------------------------------------------------*/

#ifndef NSMESH_H
#define NSMESH_H


#include <myGL\glew.h>
#include <qstring.h>
#include <global.h>
#include <vector>
#include <nsmaterial.h>

/* ---------------------------------Class NSMesh-----------------------------*

Description:
	NSMesh will load a mesh from file along with any materials that it may use.
	File formates supported are defined by the file formats in Assimp library
	as that is the library this class uses to load meshes from file.

*-------------------------------------------------------------------------------*/

// includes
#include <nsmath3d.h>
#include <nsshader.h>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <map>


// Forward declarations
class LogFile;
class NSTexture;

#ifdef DEBUG
class Debug;

#endif

class NSMesh
{
public:
	struct SubMesh
	{
		void load();
		void draw(std::vector<NSMatrix4Df> * translationMatrixes, GLenum primType, bool rebuildBuf);
		void drawSingle(const NSMatrix4Df & transform, GLenum primType, bool rebuildBuf);

		GLuint vertexArrObj;
		GLuint posBuf;
		GLuint texBuf;
		GLuint normBuf;
		GLuint tangBuf;
		GLuint indiceBuf;
		GLuint transformBuf;

		std::vector<NSVec3Df> positions;
		std::vector<NSVec2Df> texCoords;
		std::vector<NSVec3Df> normals;
		std::vector<NSVec3Df> tangents;
		std::vector<unsigned int> indices;
		std::vector<unsigned int> referenceIDs;
		std::vector<NSMatrix4Df> transforms;

		unsigned int materialIndex;
	};

	enum RenderMode { WIREFRAME, NORMAL};

	typedef aiTextureType ImportTexType;
	typedef std::vector<SubMesh*>::iterator SubMeshIter;
	typedef std::vector<SubMesh*>::const_iterator ConstSubMeshIter;

	NSMesh(const char * fileName="", const std::string & textureDir = "", bool hasTransluscentMat = false);
	~NSMesh();
	
	bool isHasTransMat();
	
	bool loadScene(const char * fileName, const std::string & textureDir = "");
	bool loadMeshes(const aiNode * node, const NSMatrix4Df & worldTransform, aiMesh ** const meshes);
	bool loadMaterial(const aiMaterial *, const std::string & textureDir);
	bool loadNodes(const aiNode * parentNode, const NSMatrix4Df & transform, const aiScene * scene); // recursive loading of scene nodes


	// 3 draws to support whichever type of draw is needed - with all matrixes multiplied
	// or supplying them seperately
	void draw(std::vector<NSMatrix4Df> * translationMatrixes, bool rebuildBuf);
	void drawSingle(const NSMatrix4Df & transform, bool rebuildBuf);

	void enableMaterialTextures(int matIndex);
	void disableMaterialTextures(int matIndex);

	void setRenderMode(RenderMode mode);
	RenderMode getRenderMode() const;
	void sortAlphaSubMeshes();

	SubMeshIter subMeshBegin();
	SubMeshIter subMeshEnd();
	ConstSubMeshIter subMeshBegin() const;
	ConstSubMeshIter subMeshEnd() const;


	#ifdef DEBUG
	void setDebug(Debug * _d);
	#endif

private:
	bool hasTransMats;
	std::string defaultTextureDir;

	std::vector<SubMesh*> subMeshes;
	std::vector<NSMaterial*> meshMaterials;
	RenderMode renderMode;

	#ifdef DEBUG
	Debug * d;
	#endif
};

#endif